package br.com.wepa.webapps.orca.logica.persistencia.hibernate;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.PersistenceException;

import br.com.wepa.webapps.orca.logica.persistencia.GenericDAO;
import br.com.wepa.webapps.orca.logica.persistencia.PersistenceDelegator;

/**
 * Hibernate Data Acess Object Generico
 */
public abstract class GenericHibernateDAO<T, ID extends Serializable> 
		implements GenericDAO<T, ID> {

	private PersistenceHibernate persistenceHibernate;
	private Class<T> persistentClass;
	private Class<ID> persistentIdClass;


	public T newInstance() {
		T instance = null;
		try {
			instance = this.persistentClass.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return instance;
	}

	public ID newIDInstance() {
		ID id = null;
		try {
			id = this.persistentIdClass.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return id;
	}

	public GenericHibernateDAO() {
		persistenceHibernate = (PersistenceHibernate) PersistenceDelegator.getHibernatePersistence();
		setPersistentClass((Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0]);
		setPersistentIdClass((Class<ID>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[1]);
	}

	public Class<T> getPersistentClass() {
		return persistentClass;
	}

	public Class<ID> getPersistentIdClass() {
		return persistentIdClass;
	}

	protected void setPersistentIdClass(Class<ID> persistentIdClass) {
		this.persistentIdClass = persistentIdClass;
	}

	protected void setPersistentClass(Class<T> persistentClass) {
		this.persistentClass = persistentClass;
	}

	/**
	 * 
	 * @param id
	 * @param lock
	 * @return the entity, must return null if not found
	 * @throws PersistenceException 
	 */
	@SuppressWarnings("unchecked")
	public T findById(ID id, boolean lock) throws PersistenceException {	
		return (T)persistenceHibernate.findById(persistentClass, id, lock);
	}	
	
	@SuppressWarnings("unchecked")
	public List<T> findAll() throws PersistenceException{
		return persistenceHibernate.findByCriteria(persistentClass);
	}

	
	@SuppressWarnings("unchecked")
	public List<T> findByExample(T exampleInstance, String... excludeProperty) throws PersistenceException {		
		return persistenceHibernate.findByExample(exampleInstance, excludeProperty);
	}

	@SuppressWarnings("unchecked")
	public T findUnique(T exampleInstance) throws PersistenceException {
		return (T) persistenceHibernate.findUnique(exampleInstance);
	}

	@SuppressWarnings("unchecked")
	public T findUnique(T exampleInstance, String... excludeProperty) throws PersistenceException {		
		return (T) persistenceHibernate.findUnique(exampleInstance, excludeProperty);
	}

	@SuppressWarnings("unchecked")
	public ID create(T entity) throws PersistenceException {		
		return (ID) persistenceHibernate.create(entity);		
	}

	public boolean exists(ID id) throws PersistenceException {
		return persistenceHibernate.findById(persistentClass,id, false) != null;
	}

	@SuppressWarnings("unchecked")
	public void refresh(T entity) throws PersistenceException {
		persistenceHibernate.refresh(entity);
	}

	@SuppressWarnings("unchecked")
	public T makePersistent(T entity) {		
		return (T)persistenceHibernate.makePersistent(entity);
	}

	public void makeTransient(T entity) throws PersistenceException {
		persistenceHibernate.makeTransient(entity);
	}

	public void flush() throws PersistenceException {
		persistenceHibernate.flushSession();
	}

	public void clear() throws PersistenceException {
		persistenceHibernate.clearSession();
	}
}
